package br.com.foxinline.servico;

import br.com.foxinline.enums.Relatorio;
import br.com.foxinline.enums.TipoPessoa;
import br.com.foxinline.modelo.*;
import br.com.foxinline.utilitario.Caracteres;
import br.com.foxinline.vo.AtoImovel;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.Query;

/**
 *
 * @author cadomeireles
 */
@Stateless
public class ImovelServico extends ServicoGenerico<Imovel> {

    public ImovelServico() {
        super(Imovel.class);
    }
    @EJB
    TransferenciaServico transferenciaServico;
    @EJB
    CartorioServico cartorioServico;

    @Override
    public void deletar(Imovel imovel) {
        imovel.setAtivo(false);
        super.atualizar(imovel);
    }

    public List<Imovel> pesquisar(String registro, Objeto objeto, Pessoa pessoa, String tipoPesquisaImovel) {

        String fromTransferencia = "";

        if (tipoPesquisaImovel.equals("A")) {
            fromTransferencia += "Transferencia transferencia join transferencia.imovel imovel join transferencia.adquirente adquirente";
        } else if (tipoPesquisaImovel.equals("T")) {
            fromTransferencia += "Transferencia transferencia join transferencia.imovel imovel join transferencia.transmitente transmitente";
        }

        String fromImovel = "Imovel imovel";

        String sql = "";

        if ((pessoa.getNome() == null || pessoa.getNome().isEmpty()) && (pessoa.getCpf() == null || pessoa.getCpf().isEmpty()) && (pessoa.getCnpj() == null || pessoa.getCnpj().isEmpty())) {
            sql += "select imovel from " + fromImovel + " where imovel.ativo = true";
        } else {
            sql += "select imovel from " + fromTransferencia + " where imovel.ativo = true and transferencia.atual = true";
        }

        if (registro != null && !registro.isEmpty()) {
            sql += " and lower(imovel.registro) like '%" + registro + "%'";
        }

        if (objeto.getEndereco().getLogradouro() != null && !objeto.getEndereco().getLogradouro().isEmpty()) {
            sql += " and lower(imovel.objeto.endereco.logradouro) like '%" + objeto.getEndereco().getLogradouro() + "%'";
        }

        if (objeto.getEndereco().getTipo() != null) {
            sql += " and imovel.objeto.endereco.tipo = :tipo";
        }

        if (objeto.getEndereco().getNumero() != null && !objeto.getEndereco().getNumero().isEmpty()) {
            sql += " and lower(imovel.objeto.endereco.numero) like '%" + objeto.getEndereco().getNumero() + "%'";
        }

//        if (objeto.getEndereco().getBairro() != null && !objeto.getEndereco().getBairro().isEmpty()) {
//            sql += " and lower(imovel.objeto.endereco.bairro) like '%" + objeto.getEndereco().getBairro() + "%'";
//        }

        if (objeto.getEndereco().getCidade() != null) {
            sql += " and imovel.objeto.endereco.cidade = :cidade";
        }

        if ((pessoa.getNome() != null && !pessoa.getNome().isEmpty())
                || (pessoa.getCpf() != null && !pessoa.getCpf().isEmpty())
                || (pessoa.getCnpj() != null && !pessoa.getCnpj().isEmpty())) {

            if (tipoPesquisaImovel.equals("A")) {

                if (pessoa.getNome() != null && !pessoa.getNome().isEmpty()) {
                    sql += " and lower(adquirente.nome) like lower('%" + pessoa.getNome() + "%')";
                }
                if (pessoa.getCpf() != null && !pessoa.getCpf().isEmpty()) {
                    sql += " and adquirente.cpf like '%" + Caracteres.removecaracter(pessoa.getCpf()) + "%'";
                }
                if (pessoa.getCnpj() != null && !pessoa.getCnpj().isEmpty()) {
                    sql += " and adquirente.cnpj like '%" + Caracteres.removecaracter(pessoa.getCnpj()) + "%'";
                }

            } else if (tipoPesquisaImovel.equals("T")) {

                if (pessoa.getNome() != null && !pessoa.getNome().isEmpty()) {
                    sql += " and lower(transmitente.nome) like lower('%" + pessoa.getNome() + "%')";
                }
                if (pessoa.getCpf() != null && !pessoa.getCpf().isEmpty()) {
                    sql += " and transmitente.cpf like '%" + Caracteres.removecaracter(pessoa.getCpf()) + "%'";
                }
                if (pessoa.getCnpj() != null && !pessoa.getCnpj().isEmpty()) {
                    sql += " and transmitente.cnpj like '%" + Caracteres.removecaracter(pessoa.getCnpj()) + "%'";
                }

            }

        }

        Query query = getEntityManager().createQuery(sql);

        if (objeto.getEndereco().getTipo() != null) {
            query.setParameter("tipo", objeto.getEndereco().getTipo());
        }

        if (objeto.getEndereco().getCidade() != null) {
            query.setParameter("cidade", objeto.getEndereco().getCidade());
        }

        return query.getResultList();
    }

    public List<Imovel> pesquisar(Imovel imovel) {
        String sql = "select imovel from Imovel imovel where imovel.ativo = true";

        if (imovel.getRegistro() != null && !imovel.getRegistro().isEmpty()) {
            sql += " and lower(imovel.registro) like '%" + imovel.getRegistro() + "%'";
        }

        Query query = getEntityManager().createQuery(sql);

        return query.getResultList();
    }

    public List<Averbacao> obterAverbacoes(Imovel imovel) {

        String sql = "select imovel.averbacoes from Imovel imovel where imovel = :imovel";

        Query query = getEntityManager().createQuery(sql);

        if (imovel != null && imovel.getId() != null) {
            query.setParameter("imovel", imovel);
        }

        return query.getResultList();

    }

    public List<Registro> obterRegistros(Imovel imovel) {

        String sql = "select imovel.registros from Imovel imovel where imovel = :imovel";

        Query query = getEntityManager().createQuery(sql);

        if (imovel != null && imovel.getId() != null) {
            query.setParameter("imovel", imovel);
        }

        return query.getResultList();

    }

    public List<Pessoa> obterUltimoAdquirente(Imovel imovel) {
        String fromTransferencia = "Transferencia transferencia join transferencia.imovel imovel join transferencia.adquirente adquirente";

        String sql = "select adquirente from " + fromTransferencia + " where imovel = :imovel and imovel.ativo = true and transferencia.atual = true";

        Query query = getEntityManager().createQuery(sql);

        if (imovel != null && imovel.getId() != null) {
            query.setParameter("imovel", imovel);
        }

        return query.getResultList();
    }

    public Integer obterUltimoNumeroRegistro(Imovel imovel) {
        String sql = "select registro from Imovel imovel join imovel.registros registro where imovel = :imovel order by registro.numero desc";

        Query query = getEntityManager().createQuery(sql);

        query.setParameter("imovel", imovel);

        Registro registro = (Registro) query.getResultList().get(0);

        return registro.getNumero();
    }

    public Integer obterUltimoNumeroAverbacao(Imovel imovel) {
        String sql = "select averbacao from Imovel imovel join imovel.averbacoes averbacao where imovel = :imovel order by averbacao.numero desc";

        Query query = getEntityManager().createQuery(sql);

        query.setParameter("imovel", imovel);

        Integer numeroAverbacao;

        try {
            Averbacao averbacao = (Averbacao) query.getResultList().get(0);
            numeroAverbacao = averbacao.getNumero();
        } catch (Exception e) {
            numeroAverbacao = 0;
        }

        return numeroAverbacao;
    }

    public List<Imovel> pesquisarImoveisAnteriores(Imovel imovel) {
        String sql = "select imovel.imoveisAnteriores from Imovel imovel where imovel.ativo = true and imovel = :imovel";

        Query query = getEntityManager().createQuery(sql);

        if (imovel.getId() != null) {
            query.setParameter("imovel", imovel);
        }

        return query.getResultList();
    }

    public List<Anexo> pesquisarAnexos(Imovel imovel) {
        String sql = "select imovel.anexos from Imovel imovel where imovel.ativo = true and imovel = :imovel";

        Query query = getEntityManager().createQuery(sql);

        if (imovel.getId() != null) {
            query.setParameter("imovel", imovel);
        }

        return query.getResultList();
    }

    public List<Transferencia> transferencias(Imovel imovel) {
        String sql = "select transferencia from Transferencia transferencia where transferencia.imovel = :imovel";

        Query query = getEntityManager().createQuery(sql);

        if (imovel != null && imovel.getId() != null) {
            query.setParameter("imovel", imovel);
        }

        return query.getResultList();
    }

    public Transferencia transferenciaAtual(Imovel imovel) {
        String sql = "select transferencia from Transferencia transferencia where transferencia.atual = true and transferencia.imovel = :imovel";

        Query query = getEntityManager().createQuery(sql);

        if (imovel != null && imovel.getId() != null) {
            query.setParameter("imovel", imovel);
        }

        return (Transferencia) query.getSingleResult();
    }

    public List<Georreferenciamento> coordenadas(Imovel imovel) {
        String sql = "select imovel.objeto.georreferenciamento from Imovel imovel where imovel = :imovel";

        Query query = getEntityManager().createQuery(sql);

        if (imovel != null && imovel.getId() != null) {
            query.setParameter("imovel", imovel);
        }

        return query.getResultList();
    }

    public List<RegistroAnterior> pesquisarRegistrosNaoCadastrados(Imovel imovel) {
        String sql = "select imovel.registrosAnterioresNaoCadastrado from Imovel imovel where imovel = :imovel";

        Query query = getEntityManager().createQuery(sql);

        if (imovel != null && imovel.getId() != null) {
            query.setParameter("imovel", imovel);
        }

        return query.getResultList();
    }

    public List<Imovel> imoveisPertencentes(Pessoa cliente) {

        String fromTransferencia = "Transferencia transferencia join transferencia.imovel imovel join transferencia.adquirente adquirente";

        String sql = "select imovel from " + fromTransferencia + " where imovel.ativo = true and transferencia.atual = true";

        if (cliente.getTipoPessoa() == TipoPessoa.FISICA) {
            sql += " and lower(adquirente.nome) like lower('" + cliente.getNome() + "')";
            sql += " and adquirente.cpf like '" + Caracteres.removecaracter(cliente.getCpf()) + "'";
        } else {
            sql += " and lower(adquirente.razaoSocial) like lower('" + cliente.getRazaoSocial() + "')";
            sql += " and adquirente.cnpj like '" + Caracteres.removecaracter(cliente.getCnpj()) + "'";
        }

        Query query = getEntityManager().createQuery(sql);

        return query.getResultList();
    }

    public Registro obterPrimeiroRegistro(Imovel imovel) {

        String sql = "select registro from Imovel imovel join imovel.registros registro where registro.numero = 1 and imovel = :imovel";

        Query query = getEntityManager().createQuery(sql);

        if (imovel != null && imovel.getId() != null) {
            query.setParameter("imovel", imovel);
        }

        return (Registro) query.getSingleResult();

    }

    public void emitirCertidaoNegativa(Pessoa cliente) {

        RelatorioServico relatorioServico = new RelatorioServico();

        HashMap<String, Object> parametros = new HashMap<String, Object>();

        relatorioCabecalho(parametros);

        String texto = "Certifico, como me faculta a lei e a requerimento de parte interessada que revendo em meu poder a Cartório, 1º Ofício desta Cidade e Comarca de Parnaíba, Estado do Piauí, os livros Registro Geral de Imóveis, dos mesmos constatei, não existir nenhum imóvel matriculado / registrado em nome de %s %s. Dou fé.";

        String documento;
        String nome;

        if (cliente.getTipoPessoa() == TipoPessoa.FISICA) {
            documento = "portador do CPF " + cliente.getCpf();
            nome = cliente.getNome();
        } else {
            documento = "portador do CNPJ " + cliente.getCnpj();
            nome = cliente.getRazaoSocial();
        }

        texto = String.format(texto, nome, documento);

        parametros.put("texto", texto);

        relatorioServico.gerarRelatorio(parametros, null, Relatorio.CERTIDAO_NEGATIVA);

    }

    public void emitirCertidaoPositiva(List<Imovel> imoveis) {

        RelatorioServico relatorioServico = new RelatorioServico();

        HashMap<String, Object> parametros = new HashMap<String, Object>();

        relatorioCabecalho(parametros);

        StringBuilder textoTransmitente = new StringBuilder();
        StringBuilder textoAdquirente = new StringBuilder();

        List<HashMap<String, String>> certidoes = new ArrayList<HashMap<String, String>>();

        String textoBase = "Certifico, como me faculta a lei e a requerimento de parte interessado que revendo em meu poder e Cartório, %s, os Livros de Registro Geral de Imóveis, nos mesmos constatei, a existência do imóvel registrado sob Nº %s em nome de %s";
        String texto = new String();

        for (Imovel imovel : imoveis) {

            HashMap<String, String> certidao = new HashMap<String, String>();

            Transferencia transferenciaAtual = transferenciaAtual(imovel);

            for (Pessoa pessoa : transferenciaAtual.getAdquirente()) {
                textoAdquirente.append(relatorioPessoa(pessoa)).append(", ");
            }

            textoAdquirente.append("tendo por objeto da referida(o) matrícula/registro o seguinte: Um(a) ");

            textoAdquirente.append(relatorioObjeto(imovel.getObjeto()));

            texto = String.format(textoBase, parametros.get("nomeCartorio"), String.valueOf(imovel.getRegistro()), textoAdquirente);

            for (Pessoa pessoa : transferenciaAtual.getTransmitente()) {
                textoTransmitente.append(pessoa.getNome()).append(", ");

                if (pessoa.getCpf() != null && !pessoa.getCpf().isEmpty()) {
                    textoTransmitente.append("CPF ").append(adicionarMascaraCPF(pessoa.getCpf()));
                }

                textoTransmitente.append(". ");
            }

            certidao.put("texto", texto);
            certidao.put("transmitentes", String.valueOf(textoTransmitente));

            if (transferenciaAtual.getTitulo() != null) {
                certidao.put("titulo", String.valueOf(transferenciaAtual.getTitulo().getNome()));
            }

            if (transferenciaAtual.getFormaTitulo() != null) {
                certidao.put("formaTitulo", String.valueOf(transferenciaAtual.getFormaTitulo()));
            }

            Locale local = new Locale("pt", "BR");
            DateFormat dateFormat = new SimpleDateFormat("dd 'de' MMMM 'de' yyyy", local);
            parametros.put("data", dateFormat.format(new Date()));

            certidoes.add(certidao);
        }

        relatorioServico.gerarRelatorio(parametros, certidoes, Relatorio.CERTIDAO_POSITIVA);
    }

    public void emitirMatricula(Imovel imovel) {

        RelatorioServico relatorioServico = new RelatorioServico();

        HashMap<String, Object> parametros = new HashMap<String, Object>();

        StringBuilder primeiroRegistro = new StringBuilder();

        relatorioCabecalho(parametros);

        primeiroRegistro.append(relatorioObjeto(imovel.getObjeto()));

        Registro registro = obterPrimeiroRegistro(imovel);
        Transferencia primeiraTransferencia = registro.getTransferencia();

        primeiroRegistro.append(relatorioRegisto(primeiraTransferencia));

        primeiroRegistro.append(" Dou fé.");

        parametros.put("primeiroRegistro", primeiroRegistro.toString());

        List<Averbacao> averbacoes = obterAverbacoes(imovel);

        List<AtoImovel> atos = new ArrayList<AtoImovel>();

        Locale local = new Locale("pt", "BR");
        DateFormat dateFormat = new SimpleDateFormat("dd 'de' MMMM 'de' yyyy", local);

        String textoAverbacao = "AV%s/%s - %s";

        for (Averbacao averbacao : averbacoes) {

            atos.add(new AtoImovel(
                    averbacao.getNumero(),
                    String.format(textoAverbacao, averbacao.getNumero(), imovel.getRegistro(), averbacao.getDescricao()),
                    dateFormat.format(averbacao.getDataAverbacao())));

        }

        List<Registro> registros = obterRegistros(imovel);

        String textoRegistro = "R%s/%s - %s";

        for (Registro r : registros) {

            if (r.getNumero() != 1) {
                if (r.getTransferencia() == null) {

                    atos.add(new AtoImovel(
                            r.getNumero(),
                            String.format(textoRegistro, r.getNumero(), imovel.getRegistro(), r.getDescricao()),
                            dateFormat.format(r.getDataRegistro())));

                } else {

                    atos.add(new AtoImovel(
                            r.getNumero(),
                            String.format(textoRegistro, r.getNumero(), imovel.getRegistro(), relatorioRegisto(r.getTransferencia())),
                            dateFormat.format(r.getDataRegistro())));
                }
            }
        }

        atos = ordenarAtos(atos);

        parametros.put("atos", atos);

        parametros.put("SUBREPORT_DIR", "br/com/foxinline/relatorio/");

        String textoOnus = new String();

        if (!ultimaAverbacao(imovel).isOnus()) {
            textoOnus = "Livre de ônus.";
        } else {
            textoOnus = "Possui ônus.";
        }

        parametros.put("onus", textoOnus);

        parametros.put("data", dateFormat.format(new Date()));

        relatorioServico.gerarRelatorio(parametros, null, Relatorio.MATRICULA);
    }

    private List<AtoImovel> ordenarAtos(List<AtoImovel> atos) {

        List<AtoImovel> atosOrdenados = new ArrayList<AtoImovel>();

        atosOrdenados = atos;

        Collections.sort(atosOrdenados, new Comparator<AtoImovel>() {
            @Override
            public int compare(AtoImovel o1, AtoImovel o2) {
                return o1.getNumero().compareTo(o2.getNumero());
            }
        });

        return atosOrdenados;

    }

    private String relatorioRegisto(Transferencia transferencia) {

        StringBuilder texto = new StringBuilder();

        texto.append(" <b>Transmitente:<b> ");

        int contador = 1;

        for (Pessoa pessoa : transferencia.getTransmitente()) {
            texto.append(relatorioPessoa(pessoa));

            if (contador < transferencia.getTransmitente().size()) {
                texto.append(", ");
            }

            contador++;
        }

        texto.append(". <b>Aquirente:<b> ");

        contador = 1;

        for (Pessoa pessoa : transferencia.getAdquirente()) {
            texto.append(relatorioPessoa(pessoa));

            if (contador < transferencia.getAdquirente().size()) {
                texto.append(", ");
            }

            contador++;
        }

        if (transferencia.getTitulo() != null) {
            texto.append(". <b>Título:<b> ").append(transferencia.getTitulo().getNome());
        }

        if (transferencia.getFormaTitulo() != null) {
            texto.append(". <b>Forma do título:<b> ").append(transferencia.getFormaTitulo());
        }

        return texto.toString();

    }

    private String relatorioPessoa(Pessoa pessoa) {

        StringBuilder texto = new StringBuilder();

        if (pessoa.getTipoPessoa() == TipoPessoa.FISICA) {

            texto.append(pessoa.getNome()).append(", ");

            if (pessoa.getNacionalidade() != null) {
                texto.append(pessoa.getNacionalidade().getNome()).append(", ");
            }

            if (pessoa.getEstadoCivil() != null) {
                texto.append(pessoa.getEstadoCivil().getNome()).append(", ");
            }

            texto.append("residente e domiciliado no(a) ");

            if (pessoa.getEndereco().getTipoLogradouro() != null) {
                texto.append(pessoa.getEndereco().getTipoLogradouro().getNome()).append(" ");
            }

            if (pessoa.getEndereco().getLogradouro() != null && !pessoa.getEndereco().getLogradouro().isEmpty()) {
                texto.append(pessoa.getEndereco().getLogradouro()).append(", ");
            }

            if (pessoa.getEndereco().getNumero() != null && !pessoa.getEndereco().getNumero().isEmpty()) {
                texto.append("número ");
                texto.append(pessoa.getEndereco().getNumero()).append(", ");
            }

            if (pessoa.getEndereco().getBairro() != null) {
                texto.append("bairro ");
                texto.append(pessoa.getEndereco().getBairro().getNome()).append(", ");
            }

            if (pessoa.getEndereco().getLocalidade() != null && !pessoa.getEndereco().getLocalidade().isEmpty()) {
                texto.append("localidade ");
                texto.append(pessoa.getEndereco().getLocalidade()).append(", ");
            }

            if (pessoa.getEndereco().getCidade() != null) {
                texto.append(pessoa.getEndereco().getCidade().getNome()).append(", ");
                texto.append(pessoa.getEndereco().getCidade().getEstado().getNome()).append(", ");
            }

            if (pessoa.getRg() != null && !pessoa.getRg().isEmpty()) {
                texto.append("portador do RG ").append(pessoa.getRg()).append(", ");
            }

            if (pessoa.getCpf() != null && !pessoa.getCpf().isEmpty()) {
                texto.append("CPF ").append(adicionarMascaraCPF(pessoa.getCpf()));
            }

        } else {

            texto.append(pessoa.getRazaoSocial()).append(", ");

            if (pessoa.getCnpj() != null && !pessoa.getCnpj().isEmpty()) {
                texto.append("CNPJ ").append(adicionarMascaraCNPJ(pessoa.getCnpj()));
            }

        }

        return texto.toString();

    }

    private Averbacao ultimaAverbacao(Imovel imovel) {

        String sql = "select averbacao from Imovel imovel join imovel.averbacoes averbacao where imovel = :imovel order by averbacao.numero desc";

        Query query = getEntityManager().createQuery(sql);

        query.setParameter("imovel", imovel);

        return (Averbacao) query.getResultList().get(0);
    }

    private String relatorioObjeto(Objeto objeto) {

        StringBuilder texto = new StringBuilder();

        if (objeto.getEndereco().getTipo() != null) {
            texto.append(objeto.getEndereco().getTipo().getNome());
        }

        texto.append(" situado(a) na(o) ");

        if (objeto.getEndereco().getTipoLogradouro() != null) {
            texto.append(objeto.getEndereco().getTipoLogradouro().getNome()).append(" ");
        }

        if (objeto.getEndereco().getLogradouro() != null && !objeto.getEndereco().getLogradouro().isEmpty()) {
            texto.append(objeto.getEndereco().getLogradouro()).append(", ");
        }

        if (objeto.getEndereco().getNumero() != null && !objeto.getEndereco().getNumero().isEmpty()) {
            texto.append("número ");
            texto.append(objeto.getEndereco().getNumero()).append(", ");
        }

        if (objeto.getEndereco().getBairro() != null) {
            texto.append("bairro ");
            texto.append(objeto.getEndereco().getBairro().getNome()).append(", ");
        }

        if (objeto.getEndereco().getLocalidade() != null && !objeto.getEndereco().getLocalidade().isEmpty()) {
            texto.append("localidade ");
            texto.append(objeto.getEndereco().getLocalidade()).append(", ");
        }

        texto.append("com as seguintes características e confrontações: ");

        if (objeto.getDescricao() != null && !objeto.getDescricao().isEmpty()) {
            texto.append(objeto.getDescricao());
        }

        if (objeto.getFrente() != null && !objeto.getFrente().isEmpty()) {
            texto.append(" Frente: ");
            texto.append(objeto.getFrente()).append(", ");
        }

        if (objeto.getLadoDireito() != null && !objeto.getLadoDireito().isEmpty()) {
            texto.append("lado direito: ");
            texto.append(objeto.getLadoDireito()).append(", ");
        }

        if (objeto.getLadoEsquerdo() != null && !objeto.getLadoEsquerdo().isEmpty()) {
            texto.append("lado esquerdo: ");
            texto.append(objeto.getLadoEsquerdo()).append(", ");
        }

        if (objeto.getFundo() != null && !objeto.getFundo().isEmpty()) {
            texto.append("fundo: ");
            texto.append(objeto.getFundo()).append(".");
        }

        return texto.toString();

    }

    private void relatorioCabecalho(HashMap<String, Object> parametros) {
        Cartorio cartorio = cartorioServico.obterCartorio();
        Endereco endereco = cartorio.getEndereco();

        parametros.put("nomeCartorio", cartorio.getRazaoSocial());
        parametros.put("titular", cartorio.getTitular().getNome());
        parametros.put("enderecoCartorio", endereco.getTipoLogradouro().getNome() + " " + endereco.getLogradouro() + ", " + endereco.getBairro().getNome());
        parametros.put("numeroCartorio", endereco.getNumero());
        parametros.put("cidadeCartorio", endereco.getCidade().getNome());
        parametros.put("estadoCartorio", endereco.getCidade().getEstado().getNome());
    }

    public String adicionarMascaraCPF(String string) {
        return Caracteres.adicionarMascara(string, Caracteres.cpfMask);
    }

    public String adicionarMascaraCNPJ(String string) {
        return Caracteres.adicionarMascara(string, Caracteres.cnpjMask);
    }
}
